package com.asen.commons.core.base.service.impl;

import com.asen.commons.core.base.domain.TreeBase;
import com.asen.commons.core.base.service.TreeBaseService;
import com.asen.commons.core.meta.dao.Condition;
import com.asen.commons.core.meta.dao.FilterGroup;
import com.asen.commons.core.meta.enums.FilterRelationEnum;
import com.asen.commons.core.utils.EntityUtils;
import com.asen.commons.utils.BaseAssert;

import java.util.List;

/**
 * 树型service抽象类
 *
 * @author Gary
 * @version 1.0
 * @date 2018-12-10
 */
public abstract class AbstractTreeBaseServiceImpl<T extends TreeBase> extends AbstractBaseDataServiceImpl<T> implements TreeBaseService<T> {

    @Override
    protected void beforeAdd(T model) throws Exception {
        super.beforeAdd(model);
        if (model.getIsLeaf() == null) {
            model.setIsLeaf(Boolean.TRUE);
        }
    }

    @Override
    protected void afterAdd(T model) throws Exception {
        super.afterAdd(model);
        checkAndUpdateParent(model, false);
    }

    @Override
    protected void afterUpdate(T model) throws Exception {
        super.afterUpdate(model);
        checkAndUpdateParent(model, true);
    }

    /**
     * 检查并更新parent相关属性
     *
     * @param model
     * @param isUpdate
     * @throws Exception
     */
    protected void checkAndUpdateParent(T model, boolean isUpdate) throws Exception {
        BaseAssert.notNull(model, "Model参数不能为空");

        if (EntityUtils.isEmpty(model.getParentId())) {
            if (isUpdate) {
                T dbModel = get(model.getId());
                if (dbModel.getParentId() == null) {
                    return;
                }
                model.setParentIds(null);
                checkAndUpdateDbParent(dbModel);
            }
            return;
        }

        T parent = get(model.getParentId());
        String parentIds = parent.getParentIds();

        if (parentIds != null && parentIds.length() > 0) {
            parentIds += ",";
        } else {
            parentIds = "";
        }
        parentIds += parent.getId();
        model.setParentId(parent.getId());
        model.setParentIds(parentIds);
        parent.setIsLeaf(Boolean.FALSE);

        if (isUpdate) {
            T dbModel = get(model.getId());
            if (!dbModel.getParentId().equals(parent.getId())) {
                checkAndUpdateDbParent(dbModel);
            }
        }

        updatePartial(parent, "isLeaf");
    }

    private void checkAndUpdateDbParent(T dbModel) throws Exception {
        Condition condition = new Condition();
        condition.equal("parentId", dbModel.getParentId());
        condition.notEqual("id", dbModel.getId());
        if (count(condition) == 0) {
            T dbParent = getModelClass().newInstance();
            dbParent.setId(dbModel.getParentId());
            dbParent.setIsLeaf(Boolean.TRUE);
            updatePartial(dbParent, "isLeaf");
        }
    }

    @Override
    public List<T> treeList(Condition condition, Integer nodeId) throws Exception {
        if (nodeId != null && nodeId > 0) {
            FilterGroup group = new FilterGroup();
            group.setFilterRelation(FilterRelationEnum.OR);
            group.equal("id", nodeId);
            group.equal("parentIds", nodeId);
            group.leftLike("parentIds", nodeId + ",");
            condition.addFilterGroup(group);
        }

        return getList(condition);
    }
}
